home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagd_f.zip / DRIVES.SWG / 0090_Read-Write Sectors-Boot Records.pas < prev    next >
Pascal/Delphi Source File  |  1995-03-03  |  10KB  |  278 lines

  1. {
  2. > I'm programming in BP 7.0 and would like to know how one can read/write
  3. > some clusters, sectors and boot records from a disk (hard or flop).
  4.  
  5. You need the dos interrupts $25 and $26. But, they have a quirk, they don't
  6. pop off the flags register (which is stored by the INT instruction).
  7. Also, you need to know which calling method you need, with 16 bit or 32 bit
  8. cluster numbers.
  9. }
  10. { Some proc's to read/write sectors, PD by Arne de Bruijn }
  11. uses Dos,Strings;
  12. type
  13.  JmpRec=record       { The starting jump in the bootsector }
  14.   Code:byte; { $E9 XX XX / $EB XX XX}
  15.   case byte of
  16.    0:(Adr1:byte; NOP:byte);
  17.    1:(Adr2:word);
  18.  end;
  19.  BpbRec=record       { The Bios Data Block (returned by DOS, and stored in }
  20. BytesPSec:word;    { the bootsector }  SecPClus:byte;
  21.   ResSec:word;
  22.   NrFATs:byte;
  23.   NrROOT:word;
  24.   TotalSec:word;
  25.   MDB:byte;
  26.   SecPFAT:word;
  27.   SecPSpoor:word;
  28.   NrHead:word;
  29.   HidSec32:longint;
  30.   TotalSec32:longint;
  31.  end;
  32.  BootSec=record      { The bootsector format in DOS }
  33.   JmpCode:JmpRec;
  34.   Name:array[0..7] of char; { Isn't meaningfull at all, just FORMAT prg name }
  35.   Bpb:BpbRec;
  36.  end;
  37.  BootSecP=^BootSec;
  38. var
  39.  BigPart:boolean;                 { 32-bit sectors? }
  40.  Drive:byte;                      { which drive are we using }
  41.  ROOTSec,FATSec,DataSec:longint;  { Some starting sectors }
  42.  FAT12:boolean;                   { 12-bit FAT? }
  43.  LastSecNo:longint;               { Save last sector number... }
  44.  LastError:word;                  { ... and error code for error report }
  45.  
  46. function ReadSec(SecNo:longint; var Buf):boolean; assembler;
  47. { Read a sector using DOS int 25h }
  48. { Parameters: }
  49. {  SecNo   Sector number to read }
  50. {  Buf     Your buffer to receive the data (512 bytes will be stored here, }
  51. {          make sure you have enough space allocated!) }
  52. { Returns TRUE if success, else FALSE }
  53. { Uses global boolean BigPart to choose between 16-bit (false) and }
  54. { 32-bit (true) sector number calling }
  55. { Uses global byte Drive to choose the drive to read from. 0=A:, 1=B: etc. }
  56. var
  57.  ParBuf:array[0..9] of byte;
  58.  { Buffer to hold parameters on 32-bit sector call: }
  59.  {  ofs size         meaning }
  60.  {   0   4 (longint) sectornumber }
  61.  {   4   2 (word)    number of sectors to read (set to 1 in this proc.) }
  62.  {   6   4 (pointer) address of buffer }
  63. asm
  64.  { Copy sectornumber to global var for error report }
  65.  mov ax,word ptr [SecNo]
  66.  mov word ptr [LastSecNo],ax
  67.  mov ax,word ptr [SecNo+2]
  68.  mov word ptr [LastSecNo+2],ax
  69.  push ds                { Store DS register (needs to be preserved in TP/BP) }
  70.  mov al,Drive           { Load Drive no. from global var (DS points still to }
  71.                         { data segment }
  72.  push ax                { Store it on stack }
  73.  cmp BigPart,0          { Must we use 32-bit calling? }
  74.  jne @DoBig             { Yes -> goto @DoBig,  No -> continue with 16-bit }
  75.  lds bx,Buf             { Load address of buffer (Buf) }
  76.  mov cx,1               { Number of sectors to read }
  77.  mov dx,word ptr [SecNo] { Get number of sector to read (SecNr) }
  78.  jmp @DosRead           { goto @DosRead, skip the 32-bit part }
  79. @DoBig:
  80.  cld                    { Store forwards in parameter buffer }
  81.  mov ax,ss              { Load address of parameter buffer (ParBuf) }
  82.  mov es,ax
  83.  mov ds,ax
  84.  lea di,ParBuf          { Still loading... }
  85.  mov bx,di              { Save offset of parameter buffer in BX }
  86.  mov ax,word ptr [SecNo] { Get number of sector to read (lo 16-bit part) }
  87.  stosw {Lo SecNr}       { Store in our buffer }
  88.  mov ax,word ptr [SecNo+2] { Get number of sector to read (hi 16-bit part) }
  89.  stosw {Hi SecNr}       { Store in buffer }
  90.  mov ax,1               { Sectors to read }
  91.  stosw                  { Store in buffer }
  92.  mov ax,word ptr [Buf]  { Get offset of buffer (Buf) }
  93.  stosw {Offset Buffer}  { Store in buffer }
  94.  mov ax,word ptr [Buf+2] { Get segment of buffer (Buf) }
  95.  stosw {Segment Buffer} { Store in buffer }
  96.  mov cx,-1              { Indicate use of 32-bit calling }
  97. @DosRead:               { Actual interrupt calling starts }
  98.  pop ax                 { Get drive number from stack }
  99.  push bp                { Save BP (must be preserved in TP/BP) }
  100.  int 25h                { DOS function: read sector(s) }
  101.  mov al,1               { Assume success (TRUE, ordinal 1) }
  102.  sbb al,0               { Subtract one if carry flag high (set on error by
  103.                         { DOS) }
  104.  popf                   { Get flags back DOS had forgotten to do }
  105.  pop bp                 { Get BP back }
  106.  pop ds                 { Get DS back }
  107.  mov LastError,ax       { Save the errorcode in global var for errorreporting }
  108. end;                    { Return to caller, al contains return code }
  109.                         { (0=FALSE, 1=TRUE) }
  110.  
  111. function WriteSec(SecNo:longint; var Buf):boolean; assembler;
  112. { Same as above, but WRITES a sector with contents of Buf }
  113. { USE WITH CAUNTION! YOU CAN DESTROY IMPORTANT DATA WITH THIS! }
  114. { (not commented, is exactly the same as ReadSec, only uses INT 26h } { instead
  115. of INT 25h) }var
  116.  ParBuf:array[0..9] of byte;
  117. asm
  118.  mov ax,word ptr [SecNo]
  119.  mov word ptr [LastSecNo],ax
  120.  mov ax,word ptr [SecNo+2]
  121.  mov word ptr [LastSecNo+2],ax
  122.  push ds
  123.  mov al,Drive
  124.  push ax
  125.  cmp BigPart,0
  126.  jne @DoBig
  127.  lds bx,Buf
  128.  mov cx,1
  129.  mov dx,word ptr [SecNo]
  130.  jmp @DosRead
  131. @DoBig:
  132.  cld
  133.  mov ax,ss
  134.  mov es,ax
  135.  mov ds,ax
  136.  lea di,ParBuf
  137.  mov bx,di
  138.  mov ax,word ptr [SecNo]
  139.  stosw {Lo SecNr}
  140.  mov ax,word ptr [SecNo+2]
  141.  stosw {Hi SecNr}
  142.  mov ax,1
  143.  stosw {Aantal Sectors}
  144.  mov ax,word ptr [Buf]
  145.  stosw {Offset Buffer}
  146.  mov ax,word ptr [Buf+2]
  147.  stosw {Segment Buffer}
  148.  mov cx,-1
  149. @DosRead:
  150.  pop ax
  151.  push bp
  152.  int 26h
  153.  mov al,1
  154.  sbb al,0
  155.  popf
  156.  pop bp
  157.  pop ds
  158.  mov LastError,ax
  159. end;
  160.  
  161. procedure DiskRError;
  162. begin
  163.  WriteLn('Error reading disk! Sector:',LastSecNo,' Errorcode:',LastError);
  164.  Halt(1);
  165. end;
  166.  
  167. var
  168.  Bpb:BpbRec; { Global copy of Bios Parameter block, for ClusToSec }
  169.  
  170. function ClusToSec(C:word):longint;
  171. { Convert clusternumber to sector number, because the cluster is often bigger }
  172. { than one sector, you need to read multiple succeeding sectors to read the }
  173. { whole cluster (number of sectors in a cluster is in BPB (BPB.SecPClus)) }
  174. { Uses global BpbRec Bpb and global longint DATASec }
  175. begin
  176.  ClusToSec:=((C-2)*Bpb.SecPClus)+DATASec;
  177. end;
  178.  
  179.  
  180. const
  181.  SizeBpb=SizeOf(BpbRec);
  182.  { Needed for assembly part, AFAIK you can't get the size of a structure }
  183.  { (record) in an asm..end; block (shame on you, Borland (or on me :-) )) }
  184. var
  185.  Buf:pointer;
  186.  S:string[1]; { To store driveletter }
  187.  I:byte;
  188. begin
  189.  I:=0;
  190.  asm
  191.   mov ax,3000h   { Get DOS version }
  192.   int 21h
  193.   cmp al,3
  194.   jb @BadDos
  195.   ja @DosOk
  196.   cmp ah,20
  197.   jae @DosOk
  198.  @BadDos:        { Lower than 3.2? }
  199.   mov I,1        { Set flag }
  200.  @DosOk:
  201.  end;
  202.  if I=1 then
  203.   begin WriteLn('Sorry, need DOS version 3.2 or higher!'); Halt(1); end;
  204.  if ParamCount=0 then
  205.   begin
  206.    WriteLn(ParamStr(0),' <driveletter>');
  207.    Halt(1);
  208.   end;
  209.  S:=ParamStr(1);
  210.  case UpCase(S[1]) of
  211.   'A'..'Z':;
  212.  else
  213.   begin
  214.    WriteLn('Bad drive!');
  215.    Halt(1);
  216.   end;
  217.  end;
  218.  Drive:=Ord(UpCase(S[1]))-65;
  219.  GetMem(Buf,512);
  220.  asm
  221.   push ds                   { Copy DS }
  222.   pop es                    { to ES }
  223.   push ds                   { Save DS }
  224.   mov ax,440dh              { DOS function 44h (IOCTL), subfunction 0Dh }
  225.                             { (blockdriver control) }
  226.   mov bl,Drive              { Driveno. }
  227.   inc bl                    { Incrase by 1 (0=default, 1=A:) }
  228.   mov cx,860h               { subsubfunction 860h (get information) }
  229.   lds dx,Buf                { Load address of buffer where to store result }
  230.   int 21h                   { Call DOS subfunction }
  231.   mov al,1                  { Assume error }
  232.   jc @EndR                  { Got error? Yes -> goto @EndR }
  233.   mov si,dx                 { Set SI on offset parameterblock }
  234.   mov al,2                  { Assume floppy }
  235.   cmp byte ptr [si+1],5     { Is it a harddisk? }
  236.   jne @EndR                 { No -> goto @EndR }
  237.   mov cx,SizeBpb            { Get size of BPB record }
  238.   add si,7                  { Starts at offset 7 in DOS parameter block }
  239.   lea di,Bpb                { Get address of our global BPB block }
  240.   cld                       { Store forwards }
  241.   rep movsb                 { Copy BPB from DOS to ours }
  242.   xor al,al                 { No errors }
  243.  @EndR:                     { AL contains errorcode: 0=no err., 1=DOS err, }
  244.                             { 2=it's a floppy (need something special) }
  245.   pop ds                    { Restore DS }
  246.   mov I,al                  { Save result }
  247.  end;
  248.  case I of
  249.   0:BigPart:=Bpb.TotalSec=0; { It's a harddisk, 16-bit field is 0 for 32-bit }
  250.                              { access }   1:                         { Error
  251. from DOS, report }   begin
  252.     WriteLn('Can''t get parameter block for drive ',chr(Drive+65),'!');
  253.     Halt(1);
  254.    end;
  255.   2:                         { It's a floppy. DOS' bpb is only right }
  256.                              { for the largest disk size, so we need to read }
  257.                              { it ourself }
  258.    begin
  259.     BigPart:=false;          { No 32-bit sectors on floppies }
  260.     if not ReadSec(0,Buf^) then  { Read bootsector (sector 0) }
  261.      DiskRError;                     { Show error if we got one }
  262.     Bpb:=BootSecP(Buf)^.Bpb;       { Copy BPB }
  263.    end;
  264.  end;
  265.  with Bpb do  {Store some handy information for accessing the disk ourself }
  266.   begin
  267.    FATSec:=ResSec;                     { Starting FAT sector }
  268.    ROOTSec:=FATSec+(NrFATs*SecPFAT);   { Starting ROOT directory sector }
  269.    DATASec:=ROOTSec+(NrROOT shr 4);    { Starting DATA sector }
  270.    if not BigPart then                 { Is it a 12-bit FAT? }
  271.     FAT12:=((TotalSec-DATASec) div SecPClus)<4087 { Yes if less than 4087 sec}
  272.    else
  273.     FAT12:=false;                      { Not with 32-bit sectors }
  274.   end;
  275.  FreeMem(Buf,512);
  276.  { do what you want }
  277. end.
  278.